#include "mydx10gameapp.h"
#include "GameObjects.h"
#include "CollisionManager.h"
#include "util_texshader.h"

//-------------------GAME IMPLEMENTATION - METHOD OVERRIDES------------------------------------------------------

/******************************************
* Implementation of our Game's Windows
* Message Pump. All types are passed to 
* the Default Windows WndProc Handler.
******************************************/
LRESULT CALLBACK CMyDX10GameApp::customWndProc(HWND pwindowhandle, UINT pmessagetype, WPARAM pwparam, LPARAM plparam)
{
	return DefWindowProc(pwindowhandle,pmessagetype,pwparam,plparam);
}
	
/******************************************
* 
******************************************/
bool CMyDX10GameApp::customInit()
{
	// Seed for Rand()
	std::srand((unsigned)time(NULL));

	// Get screen resolution
	int twidth = this->getScreenWidth();
	int theight= this->getScreenHeight();

	// Setup Timer
	this->_obj_timer.resetTimer();
	this->_obj_timer.startTimer();

/*--------------------------------
*	Input Initialisation 
---------------------------------*/
	// Build Param List for OIS to get Window ID
	ParamList			tpl;
	std::ostringstream	twndid;
	twndid << (size_t)this->_obj_wndapp->getWindowHandle();
	tpl.insert(std::make_pair(std::string("WINDOW"), twndid.str()));

	// Construct new Input Manager based off Param List
	this->_obj_inputman	= InputManager::createInputSystem(tpl);
	this->_obj_keyboard	= (Keyboard*)this->_obj_inputman->createInputObject(OISKeyboard, false);
	this->_obj_mouse	= (Mouse*)this->_obj_inputman->createInputObject(OISMouse, false);

/*----------------------------
*	Load Textures/Shaders etc
-----------------------------*/
	// Load Texture Shader
	std::wstring			tshaderfile = this->getShaderDataDir().append(L"texture.fx");
	LJMUUtilShaderTexPlain*	ttexshader	= new LJMUUtilShaderTexPlain();	
	ttexshader->initialise(_obj_dxman->getDX10Device(),tshaderfile);

	// Load Background Image, Wall Images, Player and Light Wall Sprites
	std::wstring tleveltexture	= this->getImageDataDir().append(L"Grid2.png");
	std::wstring twalltexture	= this->getImageDataDir().append(L"Walls.png");

	std::wstring tspritetexture[2];
	tspritetexture[0]			= this->getSpriteDataDir().append(L"LightCycleBlue.png");
	tspritetexture[1]			= this->getSpriteDataDir().append(L"LightCycleOrange.png");

	std::wstring tlighttexture[2];
	tlighttexture[0]			= this->getSpriteDataDir().append(L"LightWallBlue.png");
	tlighttexture[1]			= this->getSpriteDataDir().append(L"LightWallOrange.png");

/*-----------------------------------
*	Setup Objects
------------------------------------*/
	// SETUP LEVEL OBJECT
	this->_lvl_object			= new CGameObjects();
	this->_lvl_object->initialise(ttexshader, _obj_dxman->getDX10Device(), tleveltexture, 1024, 768);
	this->_lvl_object->setPos(	this->getScreenWidth()/2,
								this->getScreenHeight()/2);
	this->_lvl_object->update(1.0f);

/* SETUP WALL OBJECTS
*  Create New Wall Objects
*  Initialise Wall Objects
*  Set the Wall Objects positions - using "rand()" to set a random point on the map
*  Set the Wall Rotation
*/	
	for(int i = 0; i < NUM_OF_WALLS; i++)
	{
		this->_wall_object[i]		= new CGameObjects();
		this->_wall_object[i]->initialise(ttexshader, _obj_dxman->getDX10Device(), twalltexture, 256, 128);

		// Set all Wall Objects to bottom left corner
		this->_wall_object[i]->setPos(	0 + this->_wall_object[i]->getHalfWidth(),
										0 + this->_wall_object[i]->getHalfHeight());
		// Rotated at 180 Deg.
		this->_wall_object[i]->addRot(180.0f);
	}

	// Wall objects position re-set
	// Bottom Right Corner
	this->_wall_object[1]->setPos(	this->_wall_object[1]->getXPos() + twidth-256,
									this->_wall_object[1]->getYPos());
	
	// Top Left Corner
	this->_wall_object[2]->setPos(	this->_wall_object[2]->getXPos(),
									this->_wall_object[2]->getYPos() + theight-128);
	this->_wall_object[2]->addRot(180.0f);

	// Top Right Corner
	this->_wall_object[3]->setPos(	this->_wall_object[3]->getXPos() + twidth-256,
									this->_wall_object[3]->getYPos() + theight-128);
	this->_wall_object[3]->addRot(180.0f);

	// update wall objects
	for(int i = 0; i < NUM_OF_WALLS; i++)
		this->_wall_object[i]->update(1.0f);


/* SETUP PLAYER OBJECTS
*  Create New Player Objects
*  Set the Player Objects positions using "rand()"
*  Then seed that for the ResetPos() function to randomly set the players on the map
*/
	for(int i = 0; i < NUM_OF_PLAYERS; i++)
	{
		this->_player[i] = new CPlayerObjects();
		this->_player[i]->setPos(rand(), rand());
		this->_player[i]->resetPos(	this->_player[i]->getXPos(),
									this->_player[i]->getYPos(),
									this->_player[i]->getRot());
		this->_player[i]->setAccel(1.0f);
		this->_player[i]->setLives(10);
	}
	this->_player[0]->initialise(ttexshader, _obj_dxman->getDX10Device(), tspritetexture[0], 32, 16);
	this->_player[1]->initialise(ttexshader, _obj_dxman->getDX10Device(), tspritetexture[1], 32, 16);

/* SETUP LIGHT WALL OBJECTS
*  Create new Light Wall Objects
*  Set Position to lower left corner
*  Set Time Alive to Zero
*/
	for(int i = 0; i < NUM_OF_PLAYERS; i++)
	{
		this->_light_wall[i] = new CGameObjects();
		this->_light_wall[i]->initialise(ttexshader, _obj_dxman->getDX10Device(), tlighttexture[0], 124, 20);
		this->_light_wall[i]->setPos(	this->getScreenWidth()-this->_light_wall[i]->getWidth(),
										this->getScreenHeight()-this->_light_wall[i]->getHeight());
	}
	this->_light_wall[1]->initialise(ttexshader, _obj_dxman->getDX10Device(), tlighttexture[1], 124, 20);

	MessageBox(NULL, L"Try to survive!", L"Initialise Game...", MB_OK);

/*-------------------------------------------------------------------------------------*/

	return true;
}

/******************************************
* 
******************************************/
bool CMyDX10GameApp::customUpdate()	
{
	// Get screen resolution
	int twidth = this->getScreenWidth();
	int theight= this->getScreenHeight();
	
	// OIS uses capture to get keyboard state
	_obj_keyboard->capture();

	// Update Timer every frame
	this->_obj_timer.updateTimer();
	float ttpf	= this->_obj_timer.getTimePerFrame();

/*-----------------------
*	Player 1 Movement
------------------------*/

/*-----------------
*	Move Right
------------------*/ 
	if(_obj_keyboard->isKeyDown(KeyCode::KC_D))
	{
		// Deploy Light Wall
		if(_obj_keyboard->isKeyDown(KeyCode::KC_SPACE))
		{
			this->_light_wall[0]->setRot(0.0f);
			this->_light_wall[0]->setPos(	this->_player[0]->getXPos()-(this->_player[0]->getWidth()*2)-this->_player[0]->getHalfWidth(),
											this->_player[0]->getYPos());
		}
		else
			// Set position off screen
			this->_light_wall[0]->setPos(	this->getScreenWidth()-this->_light_wall[0]->getWidth(),
											this->getScreenHeight()-this->_light_wall[0]->getHeight());
		this->_player[0]->moveRight();
	}
/*-----------------
*	Move Left
------------------*/
	else if(_obj_keyboard->isKeyDown(KeyCode::KC_A))
	{
		// Deploy Light Wall
		if(_obj_keyboard->isKeyDown(KeyCode::KC_SPACE))
		{
			this->_light_wall[0]->setRot(0.0f);
			this->_light_wall[0]->setPos(	this->_player[0]->getXPos()+(this->_player[0]->getWidth()*2)+this->_player[0]->getHalfWidth(),
											this->_player[0]->getYPos());	
		}
		else
			// Set position off screen
			this->_light_wall[0]->setPos(	this->getScreenWidth()-this->_light_wall[0]->getWidth(),
											this->getScreenHeight()-this->_light_wall[0]->getHeight());
		this->_player[0]->moveLeft();
	}
/*-----------------
*	Move Up
------------------*/
	else if(_obj_keyboard->isKeyDown(KeyCode::KC_W))
	{
		// Deploy Light Wall
		if(_obj_keyboard->isKeyDown(KeyCode::KC_SPACE))
		{
			this->_light_wall[0]->setRot(270.0f);
			this->_light_wall[0]->setPos(	this->_player[0]->getXPos(),
											this->_player[0]->getYPos()-(this->_player[0]->getWidth()*2)-this->_player[0]->getHalfWidth());
		}
		else
			// Set position off screen
			this->_light_wall[0]->setPos(	this->getScreenWidth()-this->_light_wall[0]->getWidth(),
											this->getScreenHeight()-this->_light_wall[0]->getHeight());
		this->_player[0]->moveUp();
	}
/*-----------------
*	Move Down
------------------*/
	else if(_obj_keyboard->isKeyDown(KeyCode::KC_S))
	{
		// Deploy Light Wall
		if(_obj_keyboard->isKeyDown(KeyCode::KC_SPACE))
		{
			this->_light_wall[0]->setRot(270.0f);
			this->_light_wall[0]->setPos(	this->_player[0]->getXPos(),
											this->_player[0]->getYPos()+(this->_player[0]->getWidth()*2)+this->_player[0]->getHalfWidth());
		}
		else
			// Set position off screen
			this->_light_wall[0]->setPos(	this->getScreenWidth()-this->_light_wall[0]->getWidth(),
											this->getScreenHeight()-this->_light_wall[0]->getHeight());
		this->_player[0]->moveDown();
	}
/*-----------------------
*	Player 2 Movement
------------------------*/

/*-----------------
*	Move Right
------------------*/ 
	if(_obj_keyboard->isKeyDown(KeyCode::KC_RIGHT))
	{
		// Deploy Light Wall
		if(_obj_keyboard->isKeyDown(KeyCode::KC_NUMPAD0))
		{
			this->_light_wall[1]->setRot(0.0f);
			this->_light_wall[1]->setPos(	this->_player[1]->getXPos()-(this->_player[0]->getWidth()*2)-this->_player[1]->getHalfWidth(),
											this->_player[1]->getYPos());
		}
		else
			// Set position off screen
			this->_light_wall[1]->setPos(	this->getScreenWidth()-this->_light_wall[1]->getWidth(),
											this->getScreenHeight()-this->_light_wall[1]->getHeight());
		this->_player[1]->moveRight();
	}
/*-----------------
*	Move Left
------------------*/
	else if(_obj_keyboard->isKeyDown(KeyCode::KC_LEFT))
	{
		// Deploy Light Wall
		if(_obj_keyboard->isKeyDown(KeyCode::KC_NUMPAD0))
		{
			this->_light_wall[1]->setRot(0.0f);
			this->_light_wall[1]->setPos(	this->_player[1]->getXPos()+(this->_player[1]->getWidth()*2)+this->_player[1]->getHalfWidth(),
											this->_player[1]->getYPos());	
		}
		else
			// Set position off screen
			this->_light_wall[1]->setPos(	this->getScreenWidth()-this->_light_wall[1]->getWidth(),
											this->getScreenHeight()-this->_light_wall[1]->getHeight());
		this->_player[1]->moveLeft();
	}
/*-----------------
*	Move Up
------------------*/
	else if(_obj_keyboard->isKeyDown(KeyCode::KC_UP))
	{
		// Deploy Light Wall
		if(_obj_keyboard->isKeyDown(KeyCode::KC_NUMPAD0))
		{
			this->_light_wall[1]->setRot(270.0f);
			this->_light_wall[1]->setPos(	this->_player[1]->getXPos(),
											this->_player[1]->getYPos()-(this->_player[1]->getWidth()*2)-this->_player[1]->getHalfWidth());
		}
		else
			// Set position off screen
			this->_light_wall[1]->setPos(	this->getScreenWidth()-this->_light_wall[1]->getWidth(),
											this->getScreenHeight()-this->_light_wall[1]->getHeight());
		this->_player[1]->moveUp();
	}
/*-----------------
*	Move Down
------------------*/
	else if(_obj_keyboard->isKeyDown(KeyCode::KC_DOWN))
	{
		// Deploy Light Wall
		if(_obj_keyboard->isKeyDown(KeyCode::KC_NUMPAD0))
		{
			this->_light_wall[1]->setRot(270.0f);
			this->_light_wall[1]->setPos(	this->_player[1]->getXPos(),
											this->_player[1]->getYPos()+(this->_player[1]->getWidth()*2)+this->_player[1]->getHalfWidth());
		}
		else
			// Set position off screen
			this->_light_wall[1]->setPos(	this->getScreenWidth()-this->_light_wall[1]->getWidth(),
											this->getScreenHeight()-this->_light_wall[1]->getHeight());
		this->_player[1]->moveDown();
	}
/*----------------
*	Collision with Screen
-----------------*/
	for(int i = 0; i < NUM_OF_PLAYERS; i++)
	{
		/*---------
		* Players
		----------*/
		if(_player[i]->getXPos() >= twidth)
			this->_player[i]->scrollScreenRight(twidth);	// Right
		else if(_player[i]->getXPos() <= 0)
			this->_player[i]->scrollScreenLeft(twidth);		// Left
		if(_player[i]->getYPos() >= theight)
			this->_player[i]->scrollScreenUp(theight);		// Up
		else if(_player[i]->getYPos() <= 0)
			this->_player[i]->scrollScreenDown(theight);	// Down

		/*-----------
		* Light Walls
		------------*/
		if(_light_wall[i]->getXPos() >= twidth)
			this->_light_wall[i]->scrollScreenRight(twidth);	// Right
		else if(_light_wall[i]->getXPos() <= 0)
			this->_light_wall[i]->scrollScreenLeft(twidth);		// Left
		if(_light_wall[i]->getYPos() >= theight)
			this->_light_wall[i]->scrollScreenUp(theight);		// Up
		else if(_light_wall[i]->getYPos() <= 0)
			this->_light_wall[i]->scrollScreenDown(theight);	// Down
	}

/*--------------
*	Reset players positions
---------------*/
	
	if(_obj_keyboard->isKeyDown(KeyCode::KC_R))
		for(int i = 0; i < NUM_OF_PLAYERS; i++)
		{
			// Check if player is active
			if (_player[i]->isActive() == false)
			{
				// Set the positions using "rand()"
				// Then Reset the position based off of the random entered coords
				this->_player[i]->setPos(rand(), rand());
				this->_player[i]->resetPos(	this->_player[i]->getXPos(),
											this->_player[i]->getYPos(),
											this->_player[i]->getRot());
			}
			else
				// Randomly Reset both players positions based off of their current position
				this->_player[i]->resetPos(	this->_player[i]->getXPos(),
											this->_player[i]->getYPos(),
											this->_player[i]->getRot());
		}

/*--------------------- 
*	Collision
---------------------*/

	// temp rect for IntersectRects
	RECT temp	=	{0, 0, 0, 0};

/*--------------
*	Player/Wall
---------------*/
	for(int i = 0; i < NUM_OF_PLAYERS; i++)
		for(int j = 0; j < NUM_OF_WALLS; j++)
			if(CCollisionManager::isColliding(_player[i], _wall_object[j], &temp))
			{
				this->_player[i]->lostLives(1);
				this->_player[i]->resetPos(	this->_player[i]->getXPos(),
											this->_player[i]->getYPos(),
											this->_player[i]->getRot());
			}
/*---------------
*	Player/Player
---------------*/
	if(CCollisionManager::isColliding(_player[0], _player[1], &temp))
		for(int k = 0; k < NUM_OF_PLAYERS; k++)
		{
			this->_player[k]->lostLives(1);
			this->_player[k]->resetPos(	this->_player[k]->getXPos(),
										this->_player[k]->getYPos(),
										this->_player[k]->getRot());
		}
/*-------------------
*	Player/Light Wall
--------------------*/
	for(int m = 0; m < NUM_OF_PLAYERS; m++)		// Check Players
		for(int n = 0; n < NUM_OF_PLAYERS; n++)	// Check Light Walls
			if(CCollisionManager::isColliding(_player[m], _light_wall[n], &temp))
			{
				this->_player[m]->lostLives(1);
				this->_player[m]->resetPos(	this->_player[m]->getXPos(),
											this->_player[m]->getYPos(),
											this->_player[m]->getRot());
				this->_light_wall[n]->setPos(	this->getScreenWidth()-this->_light_wall[1]->getWidth(),
												this->getScreenHeight()-this->_light_wall[1]->getHeight());
			}

/*---------------------
*  Update all objects
----------------------*/

	// If a player has zero lives then exit the game
	for(int i = 0; i < NUM_OF_PLAYERS; i++)
		if(this->_player[i]->getLives() == 0)
		{
			MessageBox(NULL, L"You didn't survive!", L"Game Over!", MB_OK);
			exit(0);
		}

	// Update all player objects	
	for(int i = 0; i < NUM_OF_PLAYERS; i++)
		this->_player[i]->update(ttpf);

	// Update Light Wall Objects
	for(int i = 0; i < NUM_OF_PLAYERS; i++)
		this->_light_wall[i]->update(ttpf);

	// Escape to exit application
	if(_obj_keyboard->isKeyDown(KeyCode::KC_ESCAPE))
		exit(0);

	return true;
}

/******************************************
* 
******************************************/
bool CMyDX10GameApp::customRender()
{
	/*
	* Draw Order:
	* Background
	* World Objects
	* Player Objects
	* HUD (if necessary)
	*/
	// Render Level Object
	this->_lvl_object->render(1.0f, this->_dx_mat_view, this->_dx_mat_ortho);

	// Render all Light Wall Objects
	for(int i = 0; i < NUM_OF_PLAYERS; i++)
		this->_light_wall[i]->render(1.0f, this->_dx_mat_view, this->_dx_mat_ortho);

	// Render all Wall Objects
	for(int i = 0; i < NUM_OF_WALLS; i++)
		this->_wall_object[i]->render(1.0f, this->_dx_mat_view, this->_dx_mat_ortho);

	// Render all Player Objects
	for(int i = 0; i< NUM_OF_PLAYERS; i++)
		this->_player[i]->render(1.0f, this->_dx_mat_view, this->_dx_mat_ortho);

	return true;
}

/******************************************
* 
******************************************/
bool CMyDX10GameApp::customCleanup()
{
	// Cleanup all Light Wall Objects
	for(int i = 0; i < NUM_OF_PLAYERS; i++)
		this->_light_wall[i]->cleanup();

	// Cleanup all Player Objects
	for(int i = 0; i < NUM_OF_PLAYERS; i++)
		this->_player[i]->cleanup();

	// Cleanup all Wall Objects
	for(int i = 0; i < NUM_OF_WALLS; i++)
		this->_wall_object[i]->cleanup();

	return true;
}